#include "Conf.h"
#include "getConfig.h"
#include "commHeader.h"
#include <experimental/filesystem>

// namespace begin.
namespace Conf 
{

using namespace std;



static int readConf(const char* section, const char* key, std::string& val, const char* file)
{
    int res = 0;
    if ( val.empty() ) {
        char buffer[100];
        memset(buffer,'\0',sizeof(buffer));
        res = readStringValue(section,key,buffer,file);
        if ( res == 0 ) {
            val = buffer;
        }
    } else {
        res = readIntValue(section,key,file);
    }
    return res;
}

static void readBeamConf(const char* section, uint16_t* buf, const char* file)
{
    char m_file[64];
    for(int i=0;i<130;i++){
        snprintf(m_file, sizeof(m_file), "BeamCPI%d", i);
        buf[i] = readIntValue(section,m_file,file);
    }
}

static void readBeamListConf(const char* section, uint8_t* buf, int len,const char* file)
{
    uint32_t m_buffer[9];
    char m_file[64];
    for(int i=0;i<9;i++){
        snprintf(m_file, sizeof(m_file), "list%d", i);
        m_buffer[i] = readIntValue(section,m_file,file);
    }
    memcpy(buf,(uint8_t *)m_buffer,len);
}

static void readPhaseConf(const char* section, uint16_t* buf,const char* file)
{
    char m_file[64];
    for(int i=0;i<32;i++){
        snprintf(m_file, sizeof(m_file), "phase%d", i);
        buf[i] = readIntValue(section,m_file,file);
    }
}

static void readControlReg(const char* file)
{

}


ConfItem* currentConf() 
{
    static ConfItem singleton;

    return &singleton;
}

Message loadConf(const string &path) 
{
    auto conf = currentConf();
    int res = 0;

    if (path.empty()) {
        auto err = Message::create(MsgKind::FileNotExist);
        auto msg = string("file path: '") + path + "'";
        err.appendInfo(msg);

        return err;
    }
    auto confPath = path.c_str();
    auto fileName = " not found in the the Conf.ini file. ";
    std::string isReadInt = "int" ;

    res = readConf("fileSavePath","amplitudePath",
    conf->mFilePath.uAmplitudePath,confPath);

    if (res != 0 || true == conf->mFilePath.uAmplitudePath.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The amplitudePath") + fileName;
        err.appendInfo(msg);

        return err;
    }

    res = readConf("fileSavePath","freqPointPath",
    conf->mFilePath.uFreqPointPath,confPath);
    if (res != 0 || true == conf->mFilePath.uFreqPointPath.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The freqPointPath") + fileName;
        err.appendInfo(msg);

        return err;
    }

    res = readConf("fileSavePath","freq_reference_path",
    conf->mFilePath.uFreqReferencePath,confPath);
    if (res != 0 || true == conf->mFilePath.uFreqReferencePath.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The FreqReferencePath") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mParam.uFreqPoint = readConf("paramsConfig","freqPoint",isReadInt,confPath);
    if (conf->mParam.uFreqPoint < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The freqPoint") + fileName;
        err.appendInfo(msg);

        return err;
    }

    res = readConf("paramsConfig","lmx2820Dev",
    conf->mParam.uLmx2820Dev,confPath);
    if (res != 0 || true == conf->mParam.uLmx2820Dev.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The Lmx2820Dev") + fileName;
        err.appendInfo(msg);

        return err;
    }

    res = readConf("paramsConfig","ad9171Dev",
    conf->mParam.uAd9171Dev,confPath);
    if (res != 0 || true == conf->mParam.uAd9171Dev.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The ad9171Dev") + fileName;
        err.appendInfo(msg);

        return err;
    }

    /*Test_config*/
    conf->mTestConf.uInitPl = readConf("testConfig","initialPL",isReadInt,confPath);
    if (conf->mTestConf.uInitPl < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The initialPL") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mTestConf.uDarktsEnable = readConf("testConfig","darktsEnable",isReadInt,confPath);
    if (conf->mTestConf.uDarktsEnable < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The darktsEnable") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mTestConf.uStartTime = readConf("testConfig","startTiming",isReadInt,confPath);
    if (conf->mTestConf.uStartTime < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The startTiming") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mTestConf.uHrEnable = readConf("testConfig","heartbeatEnable",isReadInt,confPath);
    if (conf->mTestConf.uHrEnable < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The heartbeatEnable") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mTestConf.uCalibAnalog = readConf("testConfig","calibAnalog",isReadInt,confPath);
    conf->mTestConf.uAmpAnalog1 = readConf("testConfig","ampAnalog1",isReadInt,confPath);
    conf->mTestConf.uAmpAnalog2 = readConf("testConfig","ampAnalog2",isReadInt,confPath);
    conf->mTestConf.uPhaseAnglog1 = readConf("testConfig","phaseAnglog1",isReadInt,confPath);
    conf->mTestConf.uPhaseAnglog2 = readConf("testConfig","phaseAnglog2",isReadInt,confPath);
    if (conf->mTestConf.uCalibAnalog < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The calibAnalog") + fileName;
        err.appendInfo(msg);

        return err;
    }


    /*darktsUpdateCode*/
    conf->mDarktsCode.uSendUpdate = readConf("darktsUpdateCode","sendUpdate",isReadInt,confPath);
    if (conf->mDarktsCode.uSendUpdate < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The sendUpdate") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mDarktsCode.uReviceUpdate = readConf("darktsUpdateCode","reviceUpdate",isReadInt,confPath);
    if (conf->mDarktsCode.uReviceUpdate < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The reviceUpdate") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mDarktsCode.uSendRecvUpdate = readConf("darktsUpdateCode","sendRecvUpdate",isReadInt,confPath);
    if (conf->mDarktsCode.uSendRecvUpdate < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The sendRecvUpdate") + fileName;
        err.appendInfo(msg);

        return err;
    }
    /*GpioConfig*/
    conf->mGpioConf.uZynqBase = readConf("gpioConfig","gpioBaseAddr",isReadInt,confPath);
    if (conf->mGpioConf.uZynqBase < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The gpioBaseAddr") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mGpioConf.uPowerUp0 = readConf("gpioConfig","powerUp0",isReadInt,confPath);
    if (conf->mGpioConf.uPowerUp0 < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The powerUp0") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uPowerUp0 += conf->mGpioConf.uZynqBase;

    conf->mGpioConf.uPowerUp1 = readConf("gpioConfig","powerUp1",isReadInt,confPath);
    if (conf->mGpioConf.uPowerUp1 < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The powerUp1") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uPowerUp1 += conf->mGpioConf.uZynqBase;

    conf->mGpioConf.uPowerUp2 = readConf("gpioConfig","powerUp2",isReadInt,confPath);
    if (conf->mGpioConf.uPowerUp2 < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The powerUp2") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uPowerUp2 += conf->mGpioConf.uZynqBase;

    conf->mGpioConf.uPowerUp3 = readConf("gpioConfig","powerUp3",isReadInt,confPath);
    if (conf->mGpioConf.uPowerUp3 < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The powerUp3") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uPowerUp3 += conf->mGpioConf.uZynqBase;

    conf->mGpioConf.uPowerPz = readConf("gpioConfig","powerPz",isReadInt,confPath);
    if (conf->mGpioConf.uPowerPz < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The powerUp3") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uPowerPz += conf->mGpioConf.uZynqBase;

    conf->mGpioConf.uLedGreen = readConf("gpioConfig","ledGreen",isReadInt,confPath);
    if (conf->mGpioConf.uLedGreen < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The ledGreen") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uLedGreen += conf->mGpioConf.uZynqBase;


    conf->mGpioConf.uLedRed = readConf("gpioConfig","ledRed",isReadInt,confPath);
    if (conf->mGpioConf.uLedRed < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The ledRed") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uLedRed += conf->mGpioConf.uZynqBase;

    conf->mGpioConf.uAd9171nRST = readConf("gpioConfig","ad9171nRST",isReadInt,confPath);
    if (conf->mGpioConf.uAd9171nRST < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The ad9171nRST") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uAd9171nRST += conf->mGpioConf.uZynqBase;

    conf->mGpioConf.uAd9171TxEn0 = readConf("gpioConfig","ad9171TxEn0",isReadInt,confPath);
    if (conf->mGpioConf.uAd9171TxEn0 < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The uAd9171TxEn0") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uAd9171TxEn0 += conf->mGpioConf.uZynqBase;

    conf->mGpioConf.uAd9171TxEn1 = readConf("gpioConfig","ad9171TxEn1",isReadInt,confPath);
    if (conf->mGpioConf.uAd9171TxEn1 < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The uAd9171TxEn1") + fileName;
        err.appendInfo(msg);

        return err;
    }
    conf->mGpioConf.uAd9171TxEn1 += conf->mGpioConf.uZynqBase;

    conf->mGpioConf.uPlRfSync = readConf("gpioConfig","PL_RF_SYNC",isReadInt,confPath);
    if (conf->mGpioConf.uPlRfSync < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The PL_RF_SYNC") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mGpioConf.uPlReset = readConf("gpioConfig","PL_RESENTN_GPIO",isReadInt,confPath);
    if (conf->mGpioConf.uPlReset < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The PL_RESENTN_GPIO") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mGpioConf.uPlPllStatus = readConf("gpioConfig","PL_PLL_STATUS",isReadInt,confPath);
    if (conf->mGpioConf.uPlPllStatus < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The PL_PLL_STATUS") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mGpioConf.uPlAutoAlign = readConf("gpioConfig","PL_AUTO_ALIGN",isReadInt,confPath);
    if (conf->mGpioConf.uPlAutoAlign < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The PL_AUTO_ALIGN") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mGpioConf.uPlAdSync = readConf("gpioConfig","PL_AD_SYNC",isReadInt,confPath);
    if (conf->mGpioConf.uPlAdSync < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The PL_AD_SYNC") + fileName;
        err.appendInfo(msg);

        return err;
    }

    /*SessionConfig*/
    conf->mSessConf.uHtbPort = readConf("SessionConfig","htbPort",isReadInt,confPath);
    if (conf->mSessConf.uHtbPort < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The htbPort") + fileName;
        err.appendInfo(msg);

        return err;
    }

    res = readConf("SessionConfig","htbIp",
    conf->mSessConf.uHtbIp,confPath);
    if (res != 0 || true == conf->mSessConf.uHtbIp.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The htbIp") + fileName;
        err.appendInfo(msg);

        return err;
    }

    res = readConf("SessionConfig","localHbIp",
    conf->mSessConf.uLocalHtbIp,confPath);
    if (res != 0 || true == conf->mSessConf.uLocalHtbIp.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The localHbIp") + fileName;
        err.appendInfo(msg);

        return err;
    }


    conf->mSessConf.uCmdPort = readConf("SessionConfig","cmdPort",isReadInt,confPath);
    if (conf->mSessConf.uCmdPort < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The cmdPort") + fileName;
        err.appendInfo(msg);

        return err;
    }
    res = readConf("SessionConfig","cmdIp",
    conf->mSessConf.uCmdIp,confPath);
    if (res != 0 || true == conf->mSessConf.uCmdIp.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The cmdIp") + fileName;
        err.appendInfo(msg);

        return err;
    }
    res = readConf("SessionConfig","localCmdIp",
    conf->mSessConf.uLocalCmdIp,confPath);
    if (res != 0 || true == conf->mSessConf.uLocalCmdIp.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The localCmdIp") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mSessConf.uPcPort = readConf("SessionConfig","pcPort",isReadInt,confPath);
    if (conf->mSessConf.uPcPort < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The pcPort") + fileName;
        err.appendInfo(msg);

        return err;
    }
    res = readConf("SessionConfig","pcIp",
    conf->mSessConf.uPcIp,confPath);
    if (res != 0 || true == conf->mSessConf.uPcIp.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The pcIp") + fileName;
        err.appendInfo(msg);

        return err;
    }
    
    conf->mSessConf.uComPort = readConf("SessionConfig","comPort",isReadInt,confPath);
    if (conf->mSessConf.uComPort < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The comPort") + fileName;
        err.appendInfo(msg);

        return err;
    }
    res = readConf("SessionConfig","comIp",
    conf->mSessConf.uComIp,confPath);
    if (res != 0 || true == conf->mSessConf.uComIp.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The comIp") + fileName;
        err.appendInfo(msg);

        return err;
    }
    res = readConf("SessionConfig","localComIp",
    conf->mSessConf.uLocalComIp,confPath);
    if (res != 0 || true == conf->mSessConf.uLocalComIp.empty()) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The localComIp") + fileName;
        err.appendInfo(msg);

        return err;
    }

    conf->mLogConf.uLogOut = readConf("logConfig","logOutLevel",isReadInt,confPath);
    if (conf->mLogConf.uLogOut < 0) 
    {
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The logOutput level") + fileName;
        err.appendInfo(msg);

        return err;
    }

    /*PhaseConfig*/
    conf->mPhaseConf.uWriteNum = readConf("phaseCode","phaseWrite",isReadInt,confPath);
    if (conf->mPhaseConf.uWriteNum < 0) 
    {
        conf->mPhaseConf.uWriteNum = 0;
        auto err = Message::create(MsgKind::InvalidData);
        auto msg = string("The phaseWrite") + fileName;
        err.appendInfo(msg);

    }

    readControlReg(confPath);

    readBeamListConf("beam_queue_table", conf->mBeamConf.uBeamList, 36,confPath);
    
    readBeamConf("timing_param_bram_ctrl_beam", conf->mBeamConf.uBeamPara, confPath);
    readBeamConf("timing_param_darkts_beam", conf->mBeamConf.uDarktsBeamPara, confPath);
    readBeamConf("timing_param_bram_ctrl_RXBeam", conf->mBeamConf.uRxBeamPara, confPath);
    readBeamConf("timing_param_bram_ctrl_TXBeam", conf->mBeamConf.uTxBeamPara, confPath);
    /*PhaseConfig*/
    if (conf->mPhaseConf.uWriteNum > 0 )
    {
        readPhaseConf("phaseCode", conf->mPhaseConf.uPhaseCode, confPath);
    }
    

    return Message();

}



}